﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Npgsql;
using Szakdolgozat.Interfaces;

namespace Szakdolgozat
{
    internal class Database : IDatabase
    {
        public static NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=postgres;Password=database;Database=Szakdolgozat;");

        // a metódus megkapja, melyik táblába kell beszúrni a columns nevű stringben pedig
        // vesszővel vannak elválasztva az oszlopnevek, ezt majd az SQL kódba egyszerűen be lehet illeszteni
        // paraméterlistában pedig a tárolandó értékek vannak, nem tudni egyből, hogy milyen a típusuk
        // ezért object-ek, illetve nem tudni, hogy hány darab lesz belőlük
        // az oszlopoknál ebből nincs probléma, mert a string hossza elég nagy lehet
        public void InsertDatabase(string table, string columns, params object[] values)
        {
            // az oszlopok neve közt vessző, ellenőrzés céljából szét kell bontani
            string separator = ",";
            // az adott értékeket tartalmazó paraméterlistát a metódus összefűzi egy stringgé,
            // és az értékek közé pedig ","-t fog beszúrni, ezt már be lehet illeszteni SQL kódba
            string valuesstr = "";
            string insert = "";

            IEnumerable<string> valuescomma = values.Select(x => "'" + x + "'");
            char[] sepstring = separator.ToCharArray();
            string[] columnssep = columns.Split(sepstring, System.StringSplitOptions.None);
            conn.Open();
            // ellenőrzés, ugyanannyi oszlop van-e megadva, mint amennyi érték
            if (columnssep.Length == values.Count())
            {
                valuesstr = String.Join(separator, valuescomma);
                insert = String.Format("INSERT INTO {0} ({1}) VALUES ({2});", table, columns, valuesstr);
            }
            else
            {
                Console.WriteLine("Eltérő oszlop-, és értékszám");
            }

            NpgsqlCommand command = new NpgsqlCommand(insert, conn);
            int rows = command.ExecuteNonQuery();
            conn.Close();
        }

        // ezt a metódust lehet meghívni a GUI-ból, itt lesz a hash-kód generálása is
        public void Insertuser(string user, string password, string operatorname)
        {
            // a tábla neve, ahova a user-pw páros kerül
            string table = "operators";

            string userpw = user + password;
            int hash = userpw.GetHashCode();

            InsertDatabase(table, "operator_name,hash_codes", operatorname, hash);
        }

        // a felhasználó-jelszó páros elküldéséhez kell, hash kódként tárolódnak az adatbázisban
        public bool CheckUserPW(string user, string password)
        {
            // így alapból nem lehet bejelentkezni, csak ha tényleg egyezik a user-pw páros
            bool same = false;

            // így egy string lesz belőlük, ezt kell leelenőrizni az adatbázisban levőkkel
            string concat = user + password;
            int hash = concat.GetHashCode();

            try
            {
                conn.Open();

                //string insert = String.Format("INSERT INTO operators (hash_codes) VALUES({0})", hash);
                string query = String.Format("SELECT * FROM operators WHERE hash_codes={0}", hash);
                NpgsqlCommand command = new NpgsqlCommand(query, conn);
                var a = command.ExecuteScalar();

                if (a != null && (int)a == hash)
                {
                    return same = true;
                }
                else
                {
                    return same;
                }
            }
            finally
            {
                conn.Close();
            }
        }

        // autologin-t berakja az adatbázisba, így lehet új felhasználót regisztrálni, ha még nincs a DB-ban
        // visszatérési értéke megmondja, benne volt-e már az adatbázisban
        public bool DefaultUser()
        {
            string operatorname = "autologin";
            string userpw = "autologin" + "";
            int hash = userpw.GetHashCode();

            //try
            //{
            //    conn.Open();
            //    string query = String.Format("SELECT hash_codes FROM operators WHERE operator_name='{0}'", operatorname);
            //    NpgsqlCommand command = new NpgsqlCommand(query, conn);
            //    var a = command.ExecuteScalar();
            //    conn.Close();

            //    if (a != null && (int)a == hash)
            //    {
            //        return true;
            //    }
            //    else
            //    {
            //        this.InsertDatabase("operators", "hash_codes,operator_name", hash, operatorname);
            //        return false;
            //    }
            //}
            //finally
            //{
            //    conn.Close();
            //}
            return true;
        }

        // lekérdezéshez szükséges metódus, paraméterek: melyik táblából, mit szeretne lekérni
        /// <summary>
        /// "Select ({0}) FROM {1};"
        /// </summary>
        /// <param name="tablename"></param>
        /// <param name="columns"></param>
        /// <param name="rows"></param>
        public void Query(string tablename, string columns, out object rows)
        {
            try
            {
                conn.Open();
                string query = String.Format("Select ({0}) FROM {1};", columns, tablename);
                NpgsqlCommand command = new NpgsqlCommand(query, conn);
                rows = command.ExecuteScalar();
                conn.Close();
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// Select ({0}) FROM {1} WHERE {2}
        /// </summary>
        /// <param name="tablename"></param>
        /// <param name="columns"></param>
        /// <param name="condition"></param>
        /// <param name="rows"></param>
        public void Query(string tablename, string columns, string condition, out object rows)
        {
            try
            {
                conn.Open();
                string query = String.Format("Select ({0}) FROM {1} WHERE {2};", columns, tablename, condition);
                NpgsqlCommand command = new NpgsqlCommand(query, conn);
                rows = command.ExecuteScalar();
                conn.Close();
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// Select {0} FROM {1}, {2} WHERE {3}; Select {0} FROM {1} INNER JOIN {2} ON {3} {4} fromwhere értékétől függően
        /// </summary>
        /// <param name="first_table"></param>
        /// <param name="second_table"></param>
        /// <param name="columns"></param>
        /// <param name="condition"></param>
        /// <param name="list"></param>
        public void Query(string first_table, string second_table, string columns, string condition, out List<object> list, bool fromwhere)
        {
            string query;

            try
            {
                conn.Open();
                if (fromwhere == true)
                {
                    query = String.Format("Select {0} FROM {1}, {2} WHERE {3};",
                                                        columns, first_table, second_table, condition);
                }
                else
                {
                    query = String.Format("Select {0} FROM {1} INNER JOIN {2} ON {3} {4};",
                                                columns, first_table, second_table, first_table, condition);
                }
                NpgsqlCommand command = new NpgsqlCommand(query, conn);
                // nemcsak egy elem lekéréséről van szó
                NpgsqlDataReader reader = command.ExecuteReader();
                int j = reader.FieldCount;
                DataTable dt = reader.GetSchemaTable();
                DataRowCollection schemarows = dt.Rows;
                int i;
                list = new List<object>();
                do
                {
                    // első körben oszlopok nevének kiíratása
                    for (i = 0; i < j; i++)
                    {
                        list.Add(schemarows[i][0]);
                    }

                    // addig olvas, amíg van adat
                    while (reader.Read())
                    {
                        // soronként feltölti egy adott méréshez tartozó pad értékeket, pad váltásnál jön a köv. sor
                        for (i = 0; i < j; i++)
                        {
                            list.Add(reader[i]);
                        }
                    }
                } while (reader.NextResult());

                conn.Close();
            }
            finally
            {
                conn.Close();
            }
        }

        // több tábla összekapcsolásával adja vissza a kért értékeket
        /// <summary>
        /// "Select {0} FROM {1}, {2} WHERE {3} AND {4};"
        /// </summary>
        /// <param name="first_table"></param>
        /// <param name="second_table"></param>
        /// <param name="columns"></param>
        /// <param name="condition1"></param>
        /// <param name="condition2"></param>
        /// <param name="list"></param>
        public void Query(string first_table, string second_table, string columns, string condition1, string condition2, out List<object> list)
        {
            try
            {
                conn.Open();
                string query = String.Format("Select {0} FROM {1}, {2} WHERE {3} AND {4};",
                                                columns, first_table, second_table, condition1, condition2);
                NpgsqlCommand command = new NpgsqlCommand(query, conn);
                // nemcsak egy elem lekéréséről van szó
                NpgsqlDataReader reader = command.ExecuteReader();
                int j = reader.FieldCount;
                DataTable dt = reader.GetSchemaTable();
                DataRowCollection schemarows = dt.Rows;
                int i;
                list = new List<object>();

                do
                {
                    // első körben oszlopok nevének kiíratása
                    for (i = 0; i < j; i++)
                    {
                        list.Add(schemarows[i][0]);
                    }

                    // addig olvas, amíg van adat
                    while (reader.Read())
                    {
                        // soronként feltölti egy adott méréshez tartozó pad értékeket, pad váltásnál jön a köv. sor
                        for (i = 0; i < j; i++)
                        {
                            list.Add(reader[i]);
                        }
                    }
                } while (reader.NextResult());

                conn.Close();
            }
            finally
            {
                conn.Close();
            }
        }
    }
}